﻿using ExcelUnity.Core;
using ExcelUnity.Importer.Importers;
using ExcelUnity.Importer.Results;
using ExcelUnity.Importer.Wrappers;
using NPOI.SS.UserModel;
using System.Collections.Generic;
using System.Linq;

namespace ExcelUnity.Importer
{
    public class ExcelErrorStyleGenerator
    {
        private readonly IWorkbook _workBook;
        private readonly ICellStyle _defaultStyle;
        private readonly ICellStyle _dataErrorStyle;
        private readonly ICellStyle _rowRepeatedErrorStyle;
        private readonly ICreationHelper _commentFactory;
        private readonly IClientAnchor _commentAnchor;
        public ExcelErrorStyleGenerator(IWorkbook workBook, ErrorStyle errorStyle)
        {
            _workBook = workBook;
            _defaultStyle = _workBook.CreateCellStyle();
            _defaultStyle.FillForegroundColor = errorStyle.DefaultForegroundColor;

            _dataErrorStyle = _workBook.CreateCellStyle();
            _dataErrorStyle.FillForegroundColor = errorStyle.DataErrorForegroundColor;
            _dataErrorStyle.FillPattern = FillPattern.SolidForeground;

            _rowRepeatedErrorStyle = _workBook.CreateCellStyle();
            _rowRepeatedErrorStyle.FillForegroundColor = errorStyle.RepeatedErrorForegroundColor;
            _rowRepeatedErrorStyle.FillPattern = FillPattern.SolidForeground;

            _commentFactory = _workBook.GetCreationHelper();
            _commentAnchor = _commentFactory.CreateClientAnchor();
        }

        public void WriteSheetError(ISheet sheet, SheetWrapper sheetModel)
        {
            InitDefaultStyle(sheet, sheetModel.DataRowStartIndex!.Value);

            var commentDrawing = sheet.CreateDrawingPatriarch();
            if (sheetModel.ErrorRows.IsNotNullOrEmpty())
                SetSheetDataErrorStyle(sheet, commentDrawing, sheetModel.ErrorRows!);

            if (sheetModel.RepeatRowIndexes.IsNotNullOrEmpty())
                SetSheetRowRepeatedErrorStyle(sheet, commentDrawing, sheetModel.RepeatRowIndexes!, sheetModel.ImportSheet.UniqueValidationPrompt);
        }

        /// <summary>
        /// 将原有的与错误样式冲突的单元格样式还原
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="startDataRowIndex"></param>
        private void InitDefaultStyle(ISheet sheet, int startDataRowIndex)
        {
            for (var rowIndex = startDataRowIndex; rowIndex <= sheet.LastRowNum; rowIndex++)
            {
                var row = sheet.GetRow(rowIndex);
                foreach (var cell in row.Cells)
                {
                    cell.CellComment = null;
                    if (NeedResetToDefaultStyle(cell.CellStyle))
                        cell.CellStyle.FillForegroundColor = _defaultStyle.FillForegroundColor;
                }
            }

            bool NeedResetToDefaultStyle(ICellStyle style)
            {
                if (style == null) return false;

                return style.FillForegroundColor == _dataErrorStyle.FillForegroundColor
                    || style.FillForegroundColor == _rowRepeatedErrorStyle.FillForegroundColor;
            }
        }


        /// <summary>
        /// 错误行样式设置
        /// 设置错误单元格的样式和comment
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="commentDrawing"></param>
        /// <param name="errorRows"></param>
        private void SetSheetDataErrorStyle(ISheet sheet, IDrawing commentDrawing, IEnumerable<RowWrapper> errorRows)
        {
            foreach (var item in errorRows)
            {
                foreach (var errorCell in item.Cells.Where(x => x.Error.IsNotNullOrWhiteSpace()))
                {
                    var cell = sheet.GetRow(item.RowIndex).GetCell(errorCell.ColumnIndex) ?? sheet.GetRow(item.RowIndex).CreateCell(errorCell.ColumnIndex);

                    SetCellStyle(cell, _dataErrorStyle);

                    cell.CellComment ??= commentDrawing.CreateCellComment(_commentAnchor);

                    cell.CellComment.String = _commentFactory.CreateRichTextString(errorCell.Error);
                }
            }
        }

        /// <summary>
        /// 重复行样式设置
        /// 设置所有重复单元格的样式和重复行第一个重复列的comment
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="commentDrawing"></param>
        /// <param name="rowGroups"></param>
        /// <param name="errorPrompt"></param>
        private void SetSheetRowRepeatedErrorStyle(ISheet sheet, IDrawing commentDrawing, List<List<RepeatRow>> rowGroups, string errorPrompt)
        {
            foreach (var rowGroup in rowGroups)
            {
                foreach (var repeatRow in rowGroup)
                {
                    var row = sheet.GetRow(repeatRow.RowIndex);

                    var commented = false;
                    foreach (var columnIndex in repeatRow.ColumnIndexes)
                    {
                        var cell = row.GetCell(columnIndex);

                        SetCellStyle(cell, _rowRepeatedErrorStyle);

                        if (commented) continue;

                        if (cell.CellComment == null)
                            cell.CellComment = commentDrawing.CreateCellComment(_commentAnchor);

                        var str = $"{errorPrompt}.重复行:{string.Join(",", rowGroup.Where(m => m.RowIndex != repeatRow.RowIndex).Select(m => m.DisplayRowIndex))}";
                        cell.CellComment.String = _commentFactory.CreateRichTextString(str);
                        commented = true;
                    }
                }
            }
        }

        /// <summary>
        /// 设置单元格样式
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="errorStyle"></param>
        private void SetCellStyle(ICell cell, ICellStyle errorStyle)
        {
            if (cell.CellStyle == null)
            {
                cell.CellStyle = errorStyle;
            }
            else
            {
                var style = _workBook.CreateCellStyle();
                style.CloneStyleFrom(cell.CellStyle);
                style.FillForegroundColor = errorStyle.FillForegroundColor;
                style.FillPattern = errorStyle.FillPattern;
                cell.CellStyle = style;
            }
        }
    }
}
